package com.whfc.ms.api.base.service.impl;

import com.whfc.common.base.BaseService;
import com.whfc.common.enums.DeviceType;
import com.whfc.common.exception.BizException;
import com.whfc.common.result.ListData;
import com.whfc.common.result.ResultEnum;
import com.whfc.common.util.DateUtil;
import com.whfc.emp.dto.AppBoardEmpOverviewDTO;
import com.whfc.emp.dto.AppEmpNumDTO;
import com.whfc.emp.dto.EmpDataDTO;
import com.whfc.emp.dto.train.AppBoardEmpGroupCountDTO;
import com.whfc.emp.service.AppEmpBoardService;
import com.whfc.emp.service.AppEmpWarnService;
import com.whfc.entity.dto.board.BoardProjectDataDTO;
import com.whfc.env.service.EnvDeviceService;
import com.whfc.env.service.EnvWarnDataService;
import com.whfc.fim.service.FimResultService;
import com.whfc.fse.service.FseBoardService;
import com.whfc.fse.service.FseWarnService;
import com.whfc.fuum.dto.AppCorpDTO;
import com.whfc.fuum.dto.AppProjectDetailDTO;
import com.whfc.fuum.dto.AppStatNumDTO;
import com.whfc.fuum.service.AppCorpService;
import com.whfc.fuum.service.AppProjectService;
import com.whfc.fuum.service.SysDeptService;
import com.whfc.fuum.service.SysDictService;
import com.whfc.fvs.dto.FvsDeviceNumDTO;
import com.whfc.fvs.service.FvsDeviceService;
import com.whfc.mach.dto.AppBoardMachOverviewDTO;
import com.whfc.mach.dto.BoardMachNumDTO;
import com.whfc.mach.service.AppMachBoardService;
import com.whfc.mach.service.AppMachWarnService;
import com.whfc.ms.api.base.service.AppBoardService;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.rpc.RpcContext;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.CompletableFuture;

/**
 * 大屏展示
 *
 * @author guodong_sun
 * @Description:
 * @date 2019年9月10日
 */
@Service
public class AppBoardServiceImpl extends BaseService implements AppBoardService {

    @DubboReference(interfaceClass = AppProjectService.class, version = "1.0.0")
    private AppProjectService appProjectService;

    @DubboReference(interfaceClass = AppEmpBoardService.class, version = "1.0.0")
    private AppEmpBoardService appEmpBoardService;

    @DubboReference(interfaceClass = AppCorpService.class, version = "1.0.0")
    private AppCorpService appCorpService;

    @DubboReference(interfaceClass = SysDictService.class, version = "1.0.0")
    private SysDictService sysDictService;

    @DubboReference(interfaceClass = AppEmpWarnService.class, version = "1.0.0")
    private AppEmpWarnService appEmpWarnService;

    @DubboReference(interfaceClass = AppMachBoardService.class, version = "1.0.0")
    private AppMachBoardService appMachBoardService;

    @DubboReference(interfaceClass = FvsDeviceService.class, version = "1.0.0")
    private FvsDeviceService fvsDeviceService;

    @DubboReference(interfaceClass = FimResultService.class, version = "1.0.0")
    private FimResultService fimResultService;

    @DubboReference(interfaceClass = EnvDeviceService.class, version = "1.0.0")
    private EnvDeviceService envDeviceService;

    @DubboReference(interfaceClass = EnvWarnDataService.class, version = "1.0.0")
    private EnvWarnDataService envWarnDataService;

    @DubboReference(interfaceClass = FseBoardService.class, version = "1.0.0")
    private FseBoardService fseBoardService;

    @DubboReference(interfaceClass = FseWarnService.class, version = "1.0.0")
    private FseWarnService fseWarnService;

    @DubboReference(interfaceClass = SysDeptService.class, version = "1.0.0")
    private SysDeptService sysDeptService;

    @DubboReference(interfaceClass = AppMachWarnService.class, version = "1.0.0")
    private AppMachWarnService appMachWarnService;

    @Override
    public AppProjectDetailDTO projectOverview(Integer deptId) {
        AppProjectDetailDTO appProjectDetailDTO = appProjectService.detail(deptId);
        if (appProjectDetailDTO == null) {
            throw new BizException(ResultEnum.FAILURE.getCode(), "项目不存在！");
        }

        // 安全施工天数
        Date startDate = appProjectDetailDTO.getStartDate();
        Date endTime = new Date();
        if (startDate == null || startDate.getTime() > endTime.getTime()) {
            appProjectDetailDTO.setSafeDays(0);
        } else {
            int safeDays = DateUtil.getDaysBettweenDate(startDate, endTime);
            appProjectDetailDTO.setSafeDays(safeDays);
        }

        // 查询合作单位
        List<AppCorpDTO> corpDTOList = appCorpService.list(deptId);
        Map<Integer, Integer> corpNumMap = new HashMap<>();
        for (AppCorpDTO corpDTO : corpDTOList) {
            Integer corpTypeId = corpDTO.getCorpTypeId();
            if (corpNumMap.containsKey(corpTypeId)) {
                corpNumMap.put(corpTypeId, corpNumMap.get(corpTypeId) + 1);
            } else {
                corpNumMap.put(corpTypeId, 1);
            }
        }

        List<AppStatNumDTO> corpNumList = new ArrayList<>();
        Set<Integer> keySet = corpNumMap.keySet();
        for (Integer corpTypeId : keySet) {
            String name = sysDictService.getDictName(corpTypeId);
            AppStatNumDTO statNumDTO = new AppStatNumDTO();
            statNumDTO.setName(name);
            statNumDTO.setNum(corpNumMap.get(corpTypeId));
            corpNumList.add(statNumDTO);
        }
        //合作单位根据数量排序
        Collections.sort(corpNumList, Comparator.comparing(AppStatNumDTO::getNum));
        appProjectDetailDTO.setCorpNumList(corpNumList);

        return appProjectDetailDTO;
    }

    @Override
    public BoardProjectDataDTO getProjectLatestData(Integer deptId) {
        List<Integer> deptIds = sysDeptService.getDescendantDeptIdList(deptId);
        BoardProjectDataDTO data = new BoardProjectDataDTO();
        // 统计设备数据
        this.statMachNum(data, deptId);
        // 统计特种设备数据
        this.statFseNum(data, deptIds);
        // 环境设备数据统计
        this.statEnvNum(data, deptIds);
        // 视频设备数据统计
        this.statFvsNum(data, deptIds);
        // 人员统计数据
        this.statEmpNum(data, deptIds);

        Date endTime = new Date();
        Date startTime = DateUtil.addHours(endTime, -24);
        // 查询设备报警数
        this.statMachWarnNum(data, deptIds, startTime, endTime);
        // 查询特种设备报警数
        this.statFseWarnNum(data, deptIds, startTime, endTime);
        // 查询人员报警数
        this.statEmpWarnNum(data, deptIds, startTime, endTime);
        // 查询环境报警数
        this.statEnvWarnNum(data, deptIds, startTime, endTime);
        // 查询智能监控报警数
        this.statFimWarnNum(data, deptIds, startTime, endTime);
        return data;
    }

    @Override
    public AppBoardMachOverviewDTO machRunData(Integer deptId, Date startDate, Date endDate) {
        return appMachBoardService.machRunData(deptId, startDate, endDate);
    }

    @Override
    public AppBoardMachOverviewDTO machList(Integer deptId) {
        return appMachBoardService.machList(deptId);
    }

    @Override
    public AppBoardEmpOverviewDTO getEmpData(Integer deptId) {
        return appEmpBoardService.getEmpData(deptId);
    }

    @Override
    public ListData<EmpDataDTO> getAttendData(Integer deptId, Date startDate, Date endDate) {
        List<EmpDataDTO> list = appEmpBoardService.getAttendData(deptId, startDate, endDate);
        return new ListData<>(list);
    }

    @Override
    public List<AppBoardEmpGroupCountDTO> getEmpGroupData(Integer deptId) {
        return appEmpBoardService.countGroupData(deptId);
    }

    /**
     * 设备统计数据
     *
     * @param data
     */
    private void statMachNum(BoardProjectDataDTO data, Integer deptId) {
        int machNum = 0;
        int machOnline = 0;
        try {
            CompletableFuture<BoardMachNumDTO> machNumDTOCompletableFuture = RpcContext.getContext().asyncCall(() -> appMachBoardService.statMachNum(deptId));
            BoardMachNumDTO boardMachNumDTO = machNumDTOCompletableFuture.get();
            if (boardMachNumDTO != null) {
                machNum = boardMachNumDTO.getNum();
                machOnline = boardMachNumDTO.getOnlineNum();
            }
        } catch (Exception e) {
            logger.error("大屏获取设备统计数据失败,{}", e);
        }
        // 项目的总设备数
        data.setMachNum(machNum);
        // 项目的在线设备数
        data.setMachOnlineNum(machOnline);
    }


    /**
     * 特种设备统计数据
     *
     * @param data
     */
    private void statFseNum(BoardProjectDataDTO data, List<Integer> deptIds) {
        int num = 0;
        try {
            CompletableFuture<Integer> future = RpcContext.getContext().asyncCall(() -> fseBoardService.getFseNum(deptIds));
            num = future.get();
        } catch (Exception e) {
            logger.error("大屏获取特种设备统计数据失败,{}", e);
        }
        // 项目的总特种设备数
        data.setFseNum(num);
        // 项目的在线特种设备
        data.setFseOnlineNum(num);
    }

    /**
     * 环境设备统计数据
     *
     * @param data
     */
    private void statEnvNum(BoardProjectDataDTO data, List<Integer> deptIds) {
        int num = 0;
        try {
            CompletableFuture<Integer> future = RpcContext.getContext().asyncCall(() -> envDeviceService.getEnvDustNum(deptIds));
            num = future.get();
        } catch (Exception e) {
            logger.error("大屏获取环境设备统计数据失败,{}", e);
        }
        // 项目的总环境设备数
        data.setDustNum(num);
        // 项目的在线环境设备数
        data.setDustOnlineNum(num);
    }

    /**
     * 视频设备统计数据
     *
     * @param data
     */
    private void statFvsNum(BoardProjectDataDTO data, List<Integer> deptIds) {
        int fvsNum = 0;
        int fvsOnlineNum = 0;
        try {

            CompletableFuture<FvsDeviceNumDTO> future = RpcContext.getContext().asyncCall(() -> fvsDeviceService.getFvsDeviceNum(deptIds));
            FvsDeviceNumDTO fvsDeviceNumDTO = future.get();
            if (fvsDeviceNumDTO != null) {
                fvsNum = fvsDeviceNumDTO.getFvsNum();
                fvsOnlineNum = fvsDeviceNumDTO.getFvsOnlineNum();
            }
        } catch (Exception e) {
            logger.error("大屏获取视频设备统计数据失败,{}", e);
        }
        // 项目视频设备总数
        data.setFvsNum(fvsNum);
        // 项目的在线视频设备数
        data.setFvsOnlineNum(fvsOnlineNum);
    }

    /**
     * 人员统计数据
     *
     * @param data
     */
    private void statEmpNum(BoardProjectDataDTO data, List<Integer> deptIds) {
        int empNum = 0;
        int empAttendNum = 0;
        try {
            CompletableFuture<AppEmpNumDTO> future = RpcContext.getContext().asyncCall(() -> appEmpBoardService.getEmpNum(deptIds));
            AppEmpNumDTO appEmpNumDTO = future.get();
            if (appEmpNumDTO != null) {
                empNum = appEmpNumDTO.getEmpNum();
                empAttendNum = appEmpNumDTO.getEmpAttendNum();
            }
        } catch (Exception e) {
            logger.error("大屏获取人员统计数据失败,{}", e);
        }
        // 项目的在岗人数
        data.setEmpNum(empNum);
        // 项目的出勤人员数
        data.setEmpAttendNum(empAttendNum);
    }

    /**
     * 统计设备报警数
     *
     * @param data
     * @param deptIds
     * @param startTime
     * @param endTime
     */
    private void statMachWarnNum(BoardProjectDataDTO data, List<Integer> deptIds, Date startTime, Date endTime) {
        int num = 0;
        try {
            CompletableFuture<Integer> future = RpcContext.getContext().asyncCall(() -> appMachWarnService.getWarnNum(deptIds, startTime, endTime));
            num = future.get();
        } catch (Exception e) {
            logger.error("大屏获取设备报警数据失败,{}", e);
        }
        data.setMachWarnNum(num);
    }

    /**
     * 统计特种设备报警数
     *
     * @param data
     * @param deptIds
     * @param startTime
     * @param endTime
     */
    private void statFseWarnNum(BoardProjectDataDTO data, List<Integer> deptIds, Date startTime, Date endTime) {
        int num = 0;
        try {
            CompletableFuture<Integer> future = RpcContext.getContext().asyncCall(() -> fseWarnService.getWarnNum(deptIds, startTime, endTime));
            num = future.get();
        } catch (Exception e) {
            logger.error("大屏获取特种设备报警数据失败,{}", e);
        }
        data.setFseWarnNum(num);
    }


    /**
     * 统计人员报警数
     *
     * @param data
     * @param deptIds
     * @param startTime
     * @param endTime
     */
    private void statEmpWarnNum(BoardProjectDataDTO data, List<Integer> deptIds, Date startTime, Date endTime) {
        int num = 0;
        try {
            CompletableFuture<Integer> future = RpcContext.getContext().asyncCall(() -> appEmpWarnService.getWarnNum(deptIds, startTime, endTime));
            num = future.get();
        } catch (Exception e) {
            logger.error("大屏获取人员报警数据失败,{}", e);
        }
        data.setEmpWarnNum(num);
    }


    /**
     * 统计环境报警数
     *
     * @param data
     * @param deptIds
     * @param startTime
     * @param endTime
     */
    private void statEnvWarnNum(BoardProjectDataDTO data, List<Integer> deptIds, Date startTime, Date endTime) {
        int envNum = 0;
        int toxicNum = 0;
        try {
            CompletableFuture<Integer> future = RpcContext.getContext().asyncCall(() -> envWarnDataService.getWarnNum(deptIds, null, startTime, endTime));
            envNum = future.get();
            CompletableFuture<Integer> future1 = RpcContext.getContext().asyncCall(() -> envWarnDataService.getWarnNum(deptIds, DeviceType.gas.getValue(), startTime, endTime));
            toxicNum = future1.get();
        } catch (Exception e) {
            logger.error("大屏获取环境报警数据失败,{}", e);
        }
        data.setEnvWarnNum(envNum);
        data.setToxicWarnNum(toxicNum);
    }


    /**
     * 统计智能监控报警数
     *
     * @param data
     * @param deptIds
     * @param startTime
     * @param endTime
     */
    private void statFimWarnNum(BoardProjectDataDTO data, List<Integer> deptIds, Date startTime, Date endTime) {
        int num = 0;
        try {
            CompletableFuture<Integer> future = RpcContext.getContext().asyncCall(() -> fimResultService.getResultTotal(deptIds, startTime, endTime));
            num = future.get();
        } catch (Exception e) {
            logger.error("大屏获取智能监控报警数据失败,{}", e);
        }
        data.setFimWarnNum(num);
    }

}
